﻿//************************************************************************************************
// Copyright © 2003-2012 Steven M. Cohn. All Rights Reserved.
//
// Facility:	Microsoft Development Environment 2012  Version 11.0.50727.1
// Environment:	Microsoft .NET Framework 4.5            Version v4.0.30319
//
// Description: The main window... Duh!
//
// Revision History:
// -Who--------------- -When---------- -What------------------------------------------------------
// Steven M. Cohn		18-Oct-2003		New
// Steven M. Cohn		10-Nov-2003		Added Site column and command-line arguments
// Steven M. Cohn		12-Oct-2004		VS.NET 2005, .NET 2.0
// Steven M. Cohn		20-Nov-2012		Refresh! VS2010 .NET 4.5 64-bit
//************************************************************************************************

namespace CookieChipper
{
	using System;
	using System.Collections;
	using System.Collections.Generic;
	using System.Media;
	using System.Windows.Forms;
	using Resx = Properties.Resources;


	/// <summary>
	/// The main window.
	/// </summary>

	internal partial class MainWindow : Form
	{
		private const string DateFormat = "MM/dd/yyyy h:mm tt";

		private Oven oven;
		private CookieState stateFilter;
		private CacheHeader header;

		private int totalCount;
		private int totalLocked;
		private string searchPhrase;


		/// <summary>
		/// Initialize the window.
		/// </summary>

		public MainWindow ()
		{
			InitializeComponent();

			CacheLocation location;
			CookieCacheProvider.GetDirectoryPath(out location);
			this.Text = Properties.Resources.AppTitle + " (" + location.GetDescription() + ")";

			cookieView.Columns[0].Tag = typeof(String);		// domain
			cookieView.Columns[1].Tag = typeof(String);		// name
			cookieView.Columns[2].Tag = typeof(Int32);		// hits
			cookieView.Columns[3].Tag = typeof(DateTime);	// accessed
			cookieView.Columns[4].Tag = typeof(DateTime);	// modified

			detailView.Columns[0].Tag = typeof(String);		// name
			detailView.Columns[1].Tag = typeof(String);		// value
			detailView.Columns[2].Tag = typeof(String);		// flags
			detailView.Columns[3].Tag = typeof(DateTime);	// created
			detailView.Columns[4].Tag = typeof(DateTime);	// expires

			if (Installer.IsInstalled())
			{
				fileInstallMenu.Image = Resx.uninstall;
				fileInstallMenu.Text = "Unregister IE add-on";
			}

			stateFilter = CookieState.Unknown;
			searchPhrase = String.Empty;

			oven = new Oven();

			try
			{
				ShowCookies();
				statusMessage.Text = String.Empty;

				//watcher.Path = CookieCacheProvider.GetDirectoryPath();
				//watcher.EnableRaisingEvents = true;
			}
			catch (System.IO.FileNotFoundException)
			{
				statusMessage.Text = "No cookies found in history cache";
			}
		}


		//========================================================================================
		// Methods
		//========================================================================================

		private void ShowCookies ()
		{
			cookieView.BeginUpdate();
			cookieView.Items.Clear();

			totalCount = 0;
			totalLocked = 0;

			using (var provider = new CookieCacheProvider())
			{
				if (provider.Open())
				{
					Cookie cookie = null;

					while ((cookie = provider.GetNext()) != null)
					{
						if (cookie.Name.Length == 0)
						{
							// skip empty records in the cache index.dat
							continue;
						}

						try
						{
							using (var reader = new CookieFileProvider(cookie.Path))
							{
								reader.LoadChips(cookie);
							}
						}
						catch (System.IO.FileNotFoundException)
						{
							cookie.State = CookieState.Phantom;
						}

						oven.Bake(cookie);

						if ((stateFilter == CookieState.Unknown) ||
							((stateFilter & cookie.State) > 0))
						{
							var item = new ListViewItem(cookie.Domain);
							item.SubItems[0].Tag = cookie.Domain;
							item.ToolTipText = cookie.Path;

							ShowCookieState(item, cookie);

							ListViewItem.ListViewSubItem subItem;

							subItem = new ListViewItem.ListViewSubItem(item, cookie.Filename);
							subItem.Tag = cookie.Filename;
							item.SubItems.Add(subItem);

							subItem = new ListViewItem.ListViewSubItem(item, cookie.Hits.ToString("N0"));
							subItem.Tag = cookie.Hits;
							item.SubItems.Add(subItem);

							subItem = new ListViewItem.ListViewSubItem(
								item, cookie.Accessed.ToString(DateFormat));
							subItem.Tag = cookie.Accessed;
							item.SubItems.Add(subItem);

							subItem = new ListViewItem.ListViewSubItem(
								item, cookie.Updated.ToString(DateFormat));
							subItem.Tag = cookie.Updated;
							item.SubItems.Add(subItem);

							item.Tag = cookie;
							item.UseItemStyleForSubItems = false;

							cookieView.Items.Add(item);

							if ((cookie.State & CookieState.Locked) > 0)
							{
								totalLocked++;
							}
						}

						totalCount++;
					}

					if (totalCount > 0)
					{
						DoSort(cookieView, null);
					}
				}

				header = provider.Header;
				header.Records = totalCount;
			}

			cookieView.EndUpdate();
			detailView.Items.Clear();

			totalMessage.Text = totalCount.ToString();
			lockedMessage.Text = totalLocked.ToString();

			ShowButtonStates();
		}


		private void ShowButtonStates ()
		{
			bool selected = (cookieView.SelectedItems.Count > 0);
			bool viable = false;
			bool locked = false;
			Cookie cookie;

			if (selected)
			{
				cookie = cookieView.SelectedItems[0].Tag as Cookie;
				if (cookie != null)
				{
					viable = ((cookie.State & (CookieState.Rogue | CookieState.Phantom)) == 0);
					locked = ((cookie.State & CookieState.Locked) > 0);

					if (viable && locked)
					{
						editLockMenu.Image = Resx.unlocked;
						editLockMenu.Text = "Unlock";
						lockButton.Image = Resx.unlocked;
						lockButton.ToolTipText = "Unlock";
					}
					else
					{
						editLockMenu.Image = Resx.locked;
						editLockMenu.Text = "Lock";
						lockButton.Image = Resx.locked;
						lockButton.ToolTipText = "Lock";
					}
				}
			}
			else
			{
				lockButton.Image = Resx.locked;
			}

			lockButton.Enabled = selected && viable;
			browseButton.Enabled = selected && viable;
			notepadButton.Enabled = selected && viable;
			deleteButton.Enabled = selected;

			fileBrowseMenu.Enabled = selected && viable;
			fileNotepadMenu.Enabled = selected && viable;
			editLockMenu.Enabled = selected && viable;
			editDeleteMenu.Enabled = selected;
		}


		private void ShowCookieState (ListViewItem item, Cookie cookie)
		{
			if ((cookie.State & CookieState.Phantom) > 0)
			{
				item.ForeColor = System.Drawing.Color.Purple;
				item.ImageIndex = 5;
			}
			else if ((cookie.State & CookieState.Rogue) > 0)
			{
				item.ForeColor = System.Drawing.Color.Purple;
				item.ImageIndex = 6;
			}
			else if ((cookie.State & CookieState.Locked) > 0)
			{
				item.ForeColor = System.Drawing.SystemColors.HotTrack;
				item.ImageIndex = 1;
			}
			else if ((cookie.State & CookieState.Favorite) > 0)
			{
				item.ForeColor = System.Drawing.Color.Red;
				item.ImageIndex = 2;
			}
			else if ((cookie.State & CookieState.Stale) > 0)
			{
				item.ImageIndex = 3;
				item.ForeColor = System.Drawing.SystemColors.GrayText;
			}
			else
			{
				item.ImageIndex = 0;
				item.ForeColor = System.Drawing.SystemColors.ControlText;
			}
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoAbout (object sender, EventArgs e)
		{
			using (var about = new AboutBox())
			{
				about.ShowDialog(this);
			}
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoBackupWizard (object sender, EventArgs e)
		{
			BackupRestoreWizard.Results result;
			using (var wizard = new BackupRestoreWizard())
			{
				wizard.ShowDialog(this);
				result = wizard.Result;
			}

			if (result == BackupRestoreWizard.Results.Restore)
			{
				ShowCookies();
			}
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoBrowse (object sender, EventArgs e)
		{
			var cookie = cookieView.SelectedItems[0].Tag as Cookie;

			string scheme;
			if ((cookie.Flags & ChipFlags.Secure) == ChipFlags.Secure)
			{
				scheme = "https://";
			}
			else
			{
				scheme = "http://";
			}

			int index = cookie.Domain.IndexOf("@");
			string domain = index > 0 ? cookie.Domain.Substring(index + 1) : cookie.Domain;

			index = domain.IndexOf("/");
			if (index > 0)
			{
				domain = domain.Substring(0, index);
			}

			try
			{
				System.Diagnostics.Process.Start(scheme + domain);
			}
			catch (Exception exc)
			{
				statusMessage.Text = exc.Message;
				SystemSounds.Beep.Play();
			}
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoClean (object sender, EventArgs e)
		{
			if (oven.Locked == 0)
			{
				DialogResult result = MessageBox.Show(
					"No cookies have been locked.  Do you want to delete all cookies?",
					"Delete All",
					MessageBoxButtons.YesNo,
					MessageBoxIcon.Warning,
					MessageBoxDefaultButton.Button2);

				if (result == DialogResult.No)
				{
					return;
				}
			}
			else
			{
				int total = cookieView.Items.Count;
				DialogResult result = MessageBox.Show(
					"Deleting " + (total - totalLocked) + " of " + cookieView.Items.Count +
						" cookies.  You cool with that?",
					"Delete Unlocked",
					MessageBoxButtons.YesNo,
					MessageBoxIcon.Warning,
					MessageBoxDefaultButton.Button2);

				if (result == DialogResult.No)
				{
					return;
				}
			}

			int count = 0;
			using (var provider = new CookieCacheProvider())
			{
				if (provider.Open())
				{
					foreach (ListViewItem item in cookieView.Items)
					{
						var cookie = item.Tag as Cookie;
						if (!oven.IsLocked(cookie))
						{
							if (provider.Delete(cookie))
							{
								if (CookieFileProvider.Delete(cookie.Path))
								{
									if ((cookie.State & CookieState.Locked) > 0)
									{
										oven.Remove(cookie);
									}
								}

								count++;
							}
						}
					}
				}
			}

			ShowCookies();

			statusMessage.Text = "Cleaned " + count + " cookies";
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoClosing (object sender, FormClosingEventArgs e)
		{
			oven.Save();
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoDelete (object sender, EventArgs e)
		{
			int count = cookieView.SelectedItems.Count;
			if (count > 0)
			{
				string text;
				if (count == 1)
				{
					text = "Delete this cookie?";
				}
				else
				{
					text = "Delete these " + count + " cookies?";
				}

				DialogResult result = MessageBox.Show(
					text,
					"Confirm Delete",
					MessageBoxButtons.YesNo,
					MessageBoxIcon.Warning,
					MessageBoxDefaultButton.Button2
					);

				if (result == DialogResult.Yes)
				{
					var crumbs = new List<ListViewItem>();
					int first = cookieView.SelectedIndices[0];

					using (var provider = new CookieCacheProvider())
					{
						if (provider.Open())
						{
							foreach (ListViewItem item in cookieView.SelectedItems)
							{
								var cookie = item.Tag as Cookie;

								if (provider.Delete(cookie))
								{
									if (CookieFileProvider.Delete(cookie.Path))
									{
										if (((cookie.State & CookieState.Locked) > 0) &&
											((cookie.State & (CookieState.Phantom|CookieState.Rogue)) == 0))
										{
											oven.Remove(cookie);
											totalLocked--;
										}

										header.Records--;
									}
								}

								crumbs.Add(item);
							}
						}
					}

					if (crumbs.Count > 0)
					{
						// remove the dead cookies from the list view

						cookieView.SelectedItems.Clear();
						cookieView.BeginUpdate();
						foreach (var crumb in crumbs)
						{
							cookieView.Items.Remove(crumb);
						}
						cookieView.EndUpdate();

						detailView.Items.Clear();

						totalCount -= crumbs.Count;
						totalMessage.Text = totalCount.ToString();

						if (totalCount > 0)
						{
							if (first <= cookieView.Items.Count - 1)
							{
								cookieView.Items[first].Selected = true;
							}
							else
							{
								cookieView.Items[cookieView.Items.Count - 1].Selected = true;
							}
						}

						statusMessage.Text = "Deleted " + count + " cookies";
					}
				}
			}
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoExit (object sender, EventArgs e)
		{
			Application.Exit();
		}


		/// <summary>
		/// Export the current list or selected items to an Excel CSV file.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoExport (object sender, EventArgs e)
		{
			bool selected = cookieView.SelectedItems.Count > 1;
			int count = selected ? cookieView.SelectedItems.Count : cookieView.Items.Count;

			string initialDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);

			var dialog = new SaveFileDialog()
			{
				CheckPathExists = true,
				DefaultExt = "csv",
				FileName = "Cookies.csv",
				Filter = "Excel file (*.csv)|*.csv",
				InitialDirectory = initialDir,
				OverwritePrompt = true,
				Title = "Export " + count + " cookies"
			};

			DialogResult result = dialog.ShowDialog();
			if (result != System.Windows.Forms.DialogResult.OK)
			{
				return;
			}

			int chipCount = 0;

			IEnumerator enumerator = selected
				? cookieView.SelectedItems.GetEnumerator()
				: cookieView.Items.GetEnumerator();

			using (var exporter = new CookieExporter(dialog.FileName))
			{
				while (enumerator.MoveNext())
				{
					var item = enumerator.Current as ListViewItem;
					Cookie cookie = item.Tag as Cookie;

					try
					{
						if (cookie.Value == null)
						{
							using (var provider = new CookieFileProvider(cookie.Path))
							{
								provider.LoadChips(cookie);
							}
						}

						chipCount += exporter.Export((Cookie)item.Tag);
					}
					catch (System.IO.FileNotFoundException)
					{
						// TODO: remove from view?
					}
				}
			}

			MessageBox.Show(
				count.ToString() + " cookies, " + chipCount + " values written to " + dialog.FileName,
				"Export complete",
				MessageBoxButtons.OK);
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoFilterFavorites (object sender, EventArgs e)
		{
			stateFilter ^= CookieState.Favorite;
			bool fav = (stateFilter & CookieState.Favorite) > 0;

			viewFavoritesMenu.Checked = fav;

			if (fav && ((stateFilter & CookieState.Locked) > 0))
			{
				stateFilter ^= CookieState.Locked;
				viewProtectedMenu.Checked = false;
			}

			ShowCookies();

			statusMessage.Text = String.Empty;
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoFilterProtected (object sender, EventArgs e)
		{
			stateFilter ^= CookieState.Locked;
			bool pro = (stateFilter & CookieState.Locked) > 0;

			viewProtectedMenu.Checked = pro;

			if (pro && ((stateFilter & CookieState.Favorite) > 0))
			{
				stateFilter ^= CookieState.Favorite;
				viewFavoritesMenu.Checked = false;
			}

			ShowCookies();

			statusMessage.Text = String.Empty;
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoInstallation (object sender, EventArgs e)
		{
			if (Installer.IsInstalled())
			{
				if (Installer.Uninstall())
				{
					fileInstallMenu.Image = Resx.install;
					fileInstallMenu.Text = "Register as IE add-on";
				}
			}
			else
			{
				if (Installer.Install())
				{
					fileInstallMenu.Image = Resx.uninstall;
					fileInstallMenu.Text = "Unregister IE add-on";
				}
			}
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoLock (object sender, EventArgs e)
		{
			foreach (ListViewItem item in cookieView.SelectedItems)
			{
				var cookie = item.Tag as Cookie;
				if ((cookie.State & CookieState.Locked) > 0)
				{
					cookie.State ^= CookieState.Locked;
					oven.Remove(cookie);
					oven.Save();
					editLockMenu.Image = Resx.locked;
					editLockMenu.Text = "Lock";
					lockButton.Image = Resx.locked;
					lockButton.ToolTipText = "Lock";
					totalLocked--;
				}
				else
				{
					cookie.State |= CookieState.Locked;
					oven.Add(cookie);
					oven.Save();
					editLockMenu.Image = Resx.unlocked;
					editLockMenu.Text = "Unlock";
					lockButton.Image = Resx.unlocked;
					lockButton.ToolTipText = "Unlock";
					totalLocked++;
				}

				ShowCookieState(item, cookie);
				lockedMessage.Text = totalLocked.ToString();
			}
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoNotepad (object sender, EventArgs e)
		{
			var cookie = cookieView.SelectedItems[0].Tag as Cookie;

			if (!String.IsNullOrEmpty(cookie.Path) && System.IO.File.Exists(cookie.Path))
			{
				try
				{
					System.Diagnostics.Process.Start(cookie.Path);
				}
				catch (Exception exc)
				{
					statusMessage.Text = exc.Message;
					SystemSounds.Beep.Play();
				}
			}
		}


		/// <summary>
		/// Initialize the state of the context menu items.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoPrepareContextMenu (object sender, System.ComponentModel.CancelEventArgs e)
		{
			ListViewItem item = cookieView.SelectedItems[0];
			var cookie = item.Tag as Cookie;
			bool viable = ((cookie.State & (CookieState.Rogue | CookieState.Phantom)) == 0);

			contextBrowse.Enabled = viable;
			contextLock.Enabled = viable;
			contextNotepad.Enabled = viable;
			contextRefresh.Enabled = ((cookie.State & CookieState.Phantom) == 0);

			if (viable && ((cookie.State & CookieState.Locked) > 0))
			{
				contextLock.Image = Resx.unlocked;
				contextLock.Text = "Unlock";
			}
			else
			{
				contextLock.Image = Resx.locked;
				contextLock.Text = "Lock";
			}
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoRefresh (object sender, EventArgs e)
		{
			ShowCookies();

			statusMessage.Text = String.Empty;
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoRefreshChips (object sender, EventArgs e)
		{
			if (cookieView.SelectedItems.Count == 0)
			{
				return;
			}

			foreach (ListViewItem item in cookieView.SelectedItems)
			{
				var cookie = item.Tag as Cookie;
				if (cookie != null)
				{
					cookie.Clear();
					DoShowChips(sender, e);
				}
			}
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoSearch (object sender, EventArgs e)
		{
			var box = new SearchBox();
			box.Top = this.Top + box.Height;
			box.Left = this.Right - box.Width - 50;
			box.SearchPhrase = searchPhrase;
			box.Search += Search;
			box.FormClosed += EndSearch;

			box.Show();
		}

		void EndSearch (object sender, FormClosedEventArgs e)
		{
			var box = sender as SearchBox;
			box.Search -= Search;
			box.FormClosed -= EndSearch;
		}


		private void Search (string text, bool forward)
		{
			int step = forward ? 1 : -1;
			int last = forward ? cookieView.Items.Count : -1;

			int saved;
			int index;

			if (cookieView.SelectedIndices.Count == 0)
			{
				saved = -1;
				index = 0;
			}
			else
			{
				saved = cookieView.SelectedIndices[0];
				index = cookieView.SelectedIndices[0] + step;
				cookieView.SelectedIndices.Clear();
			}

			ListViewItem item = null;

			while ((index != last) && (item == null))
			{
				var cookie = cookieView.Items[index].Tag as Cookie;
				if (cookie.Domain.Contains(text))
				{
					item = cookieView.Items[index];
				}
				else
				{
					index += step;
				}
			}

			if (item != null)
			{
				item.Selected = true;
				item.EnsureVisible();
			}
			else
			{
				SystemSounds.Beep.Play();

				if (saved >= 0)
				{
					cookieView.Items[saved].Selected = true;
					cookieView.Items[saved].EnsureVisible();
				}
			}

			searchPhrase = text;
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoSelectAll (object sender, EventArgs e)
		{
			foreach (ListViewItem item in cookieView.Items)
			{
				item.Selected = true;
			}

			statusMessage.Text = "Selected " + cookieView.Items.Count + " cookies";
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoShowChips (object sender, EventArgs e)
		{
			detailView.BeginUpdate();
			detailView.Items.Clear();

			if (cookieView.SelectedItems.Count > 0)
			{
				ListViewItem citem = cookieView.SelectedItems[0];
				var cookie = citem.Tag as Cookie;

				if (cookie.Value == null)
				{
					try
					{
						using (var provider = new CookieFileProvider(cookie.Path))
						{
							provider.LoadChips(cookie);
						}
					}
					catch (System.IO.FileNotFoundException)
					{
						cookie.State = CookieState.Phantom;
						ShowCookieState(citem, cookie);
					}
				}

				if (cookie.Value != null)
				{
					foreach (var chip in cookie.Values)
					{
						var item = new ListViewItem(chip.Name);
						item.SubItems[0].Tag = chip.Name;
						if ((chip.Flags & ChipFlags.Primary) > 0)
						{
							item.ImageIndex = 4;
						}
						else if ((chip.Flags & ChipFlags.Expire) > 0)
						{
							item.ImageIndex = 3;
						}

						ListViewItem.ListViewSubItem subItem;

						subItem = new ListViewItem.ListViewSubItem(item, chip.Value);
						subItem.Tag = chip.Value;
						item.SubItems.Add(subItem);

						subItem = new ListViewItem.ListViewSubItem(item, chip.Flags.ToNames());
						subItem.Tag = subItem.Text;
						item.SubItems.Add(subItem);

						subItem = new ListViewItem.ListViewSubItem(item, chip.Created.ToString(DateFormat));
						subItem.Tag = chip.Created;
						item.SubItems.Add(subItem);

						subItem = new ListViewItem.ListViewSubItem(item, chip.Expires.ToString(DateFormat));
						subItem.Tag = chip.Expires;
						item.SubItems.Add(subItem);

						detailView.Items.Add(item);
					}
				}

				if ((cookie.State & CookieState.Phantom) > 0)
				{
					statusMessage.Text = "Phantom! File not found for domain " + cookie.Domain;
				}
				else if ((cookie.State & CookieState.Rogue) > 0)
				{
					statusMessage.Text = "Rogue! Orphaned file found for domain " + cookie.Domain;
				}
				else if ((cookie.State & CookieState.Locked) > 0)
				{
					statusMessage.Text = cookie.Domain + " is protected";
				}
				else if ((cookie.State & CookieState.Favorite) > 0)
				{
					statusMessage.Text = cookie.Domain + " is related to your Favorites";
				}
				else if ((cookie.State & CookieState.Stale) > 0)
				{
					statusMessage.Text = cookie.Domain + " is expired or about to expire";
				}
				else
				{
					statusMessage.Text = String.Empty;
				}
			}

			detailView.EndUpdate();

			ShowButtonStates();
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoSort (object sender, ColumnClickEventArgs e)
		{
			var view = sender as ListView;

			var comparer = view.ListViewItemSorter as ListViewItemComparer;
			if (comparer == null)
			{
				view.ListViewItemSorter = comparer = new ListViewItemComparer(0);
				view.Sorting = SortOrder.Ascending;
			}
			else if (e == null)
			{
				// special case for Refresh, from ShowCookies, to indicate Asc
				view.Sorting = SortOrder.Ascending;
			}
			else if (e.Column != comparer.Column)
			{
				view.Sorting = SortOrder.Ascending;
			}
			else if (view.Sorting == SortOrder.Ascending)
			{
				view.Sorting = SortOrder.Descending;
			}
			else
			{
				view.Sorting = SortOrder.Ascending;
			}

			comparer.Column = (e == null ? 0 : e.Column);
			view.Sort();

			statusMessage.Text = String.Empty;
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>

		private void DoViewProperties (object sender, EventArgs e)
		{
			using (var dialog = new PropertiesWindow(header))
			{
				dialog.ShowDialog(this);
			}
		}
	}
}
